﻿using Newtonsoft.Json.Serialization;
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using JsonProperty = Newtonsoft.Json.Serialization.JsonProperty;
using System.Linq.Expressions;
using Newtonsoft.Json.Linq;

namespace fabao.Common.Util
{
    /// <summary>
    /// JSON序列化、反序列化扩展类。
    /// </summary>
    public static class JsonHelper
    {
        /// <summary>
        /// 对象序列化成JSON字符串。
        /// </summary>
        /// <param name="obj">序列化对象</param>
        /// <param name="ignoreProperties">设置需要忽略的属性</param>
        /// <returns></returns>
        public static string ToJson(this object obj, params string[] ignoreProperties)
        {
            JsonSerializerSettings settings = new JsonSerializerSettings();
            settings.Formatting = Formatting.None;
            settings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
            settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
            settings.ContractResolver = new JsonPropertyContractResolver(ignoreProperties);
            return JsonConvert.SerializeObject(obj, settings);
        }
        /// <summary>
        /// JSON字符串序列化成对象。
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="json">JSON字符串</param>
        /// <returns></returns>
        public static T ToObject<T>(this string json)
        {
            return json == null ? default(T) : JsonConvert.DeserializeObject<T>(json);
        }
        /// <summary>
        /// JSON字符串序列化成集合。
        /// </summary>
        /// <typeparam name="T">集合类型</typeparam>
        /// <param name="json">JSON字符串</param>
        /// <returns></returns>
        public static List<T> ToList<T>(this string json)
        {
            return json == null ? null : JsonConvert.DeserializeObject<List<T>>(json);
        }
        /// <summary>
        /// JSON字符串序列化成DataTable。
        /// </summary>
        /// <param name="json">JSON字符串</param>
        /// <returns></returns>
        public static DataTable ToTable(this string json)
        {
            return json == null ? null : JsonConvert.DeserializeObject<DataTable>(json);
        }

        /// <summary>
        /// 复制一个类
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static T CloneJson<T>(this T source)
        {
            if (Object.ReferenceEquals(source, null))
            {
                return default(T);
            }

            var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };
            return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
        }

        /// <summary>
        /// 将Datatable转为List
        /// </summary>
        /// <param name="type">匿名对象GetType类型</param>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static object DataTableToObj(this DataTable dt, Type type)
        {
            Type typeMaster = typeof(List<>);
            Type listType = typeMaster.MakeGenericType(type);
            IList list = Activator.CreateInstance(listType) as IList;
            if (dt == null || dt.Rows.Count == 0)
                return list;
            var constructor = type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                           .OrderBy(c => c.GetParameters().Length).First();
            var parameters = constructor.GetParameters();
            var values = new object[parameters.Length];
            foreach (DataRow dr in dt.Rows)
            {
                int index = 0;
                foreach (ParameterInfo item in parameters)
                {
                    object itemValue = null;
                    if (dr[item.Name] != null && dr[item.Name] != DBNull.Value)
                    {
                        itemValue = dr[item.Name];
                    }
                    values[index++] = itemValue;
                }
                list.Add(constructor.Invoke(values));
            }
            return list;
        }
        /// <summary>
        /// 实体列表转dic
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <returns></returns>
        public static Dictionary<string, string> ClassToDictionary<T>(List<T> t, Expression<Func<T, object>> keySelector)
    where T : class
        {
            Dictionary<string, string> item = new Dictionary<string, string>();
            var keyExpression = keySelector.Body as MemberExpression;
            if (keyExpression != null)
            {
                var keyPropertyName = keyExpression.Member.Name;

                foreach (var obj in t)
                {
                    var property = typeof(T).GetProperty(keyPropertyName);
                    if (property != null)
                    {
                        var keyValue = property.GetValue(obj)?.ToString();
                        if (!string.IsNullOrEmpty(keyValue))
                            item[keyValue] = keyValue;
                    }
                }
            }
            return item;
        }

        /// <summary>
        /// 实体列表转dic
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <returns>dic(keySelector-classJson)</returns>
        public static Dictionary<string, string> ClassToDictionaryByKey<T>(List<T> t, Expression<Func<T, object>> keySelector)
            where T : class
        {
            Dictionary<string, string> item = new Dictionary<string, string>();
            for (int i = 0; i < t.Count; i++)
            {
                string key = keySelector.Compile().Invoke(t[i])?.ToString();
                if (string.IsNullOrEmpty(key))
                {
                    throw new NullReferenceException("key值存在空");
                }
                item[key] = JsonConvert.SerializeObject(t[i]);
            }

            return item;

        }

        /// <summary>
        /// dic转实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dictionary"></param>
        /// <returns></returns>
        public static List<T> DictionaryToClass<T>(List<KeyValuePair<string, string>> dictionary) where T : new()
        {
            var list = new List<T>();

            foreach (var kvp in dictionary)
            {
                var obj = JsonConvert.DeserializeObject<T>(kvp.Value);
                if (obj == null)
                    continue;
                list.Add(obj);
            }

            return list;
        }

        /// <summary>
        /// json转dic
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        public static Dictionary<string, string> JsonToDictionary(string json)
        {
            Dictionary<string, string> result = new Dictionary<string, string>();
            JObject jObject = JObject.Parse(json);
            foreach (var property in jObject.Properties())
            {
                result.Add(property.Name, property.Value.ToString());
            }
            return result;
        }

        /// <summary>
        /// json转dic<string,object>
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        public static Dictionary<string, object> JsonToObjectValueDictionary(string json)
        {
            Dictionary<string, object> result = new Dictionary<string, object>();
            JObject jObject = JObject.Parse(json);
            foreach (var property in jObject.Properties())
            {
                result.Add(property.Name, property.Value);
            }
            return result;
        }
    }
    /// <summary>
    /// JSON分解器-设置。
    /// </summary>
    public class JsonPropertyContractResolver : DefaultContractResolver
    {
        /// <summary>
        /// 需要排除的属性。
        /// </summary>
        private IEnumerable<string> _listExclude;

        public JsonPropertyContractResolver(params string[] ignoreProperties)
        {
            this._listExclude = ignoreProperties;
        }

        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            //设置需要输出的属性。
            return base.CreateProperties(type, memberSerialization).ToList().FindAll(p => !_listExclude.Contains(p.PropertyName));
        }
    }
}
